grammar Mod;


tokens {
	NULL = 'null';
	NOMOD = 'nomod';
	VOID = 'void';
	TRUE = 'true';
	FALSE = 'false';
}

@rulecatch {
}

@header{
	package ac.jp.u_tokyo.SyncLib.modParser;
	import java.util.LinkedList;
	import java.util.List;
	import ac.jp.u_tokyo.SyncLib.*;
	import ac.jp.u_tokyo.SyncLib.dictionaries.*;



}

@members {
	public static Mod[] parse(String text) throws RecognitionException {
		ANTLRStringStream input = new ANTLRStringStream(text);
		ModLexer lexer = new ModLexer(input);
		ModParser parser = new ModParser(new CommonTokenStream(lexer));
		return parser.prog().toArray(new Mod[] {});
	}
}

@lexer::header{
package ac.jp.u_tokyo.SyncLib.modParser;
}

fragment DIGIT 
	:	'0'..'9';
	
fragment ULETTER
	:	'A'..'Z';
fragment LLETTER
	:	'a'..'z';
fragment LETTER
	:	ULETTER | LLETTER | '_' | '*';	

NUMBER : DIGIT+;
NAME 	:	LETTER (DIGIT | LETTER)*;
STRING : ('\"' | '\'') (~('\"' | '\''))* ('\"' | '\'');


WS
    : (' '|'\t' | '\n')+ {skip();}
    ; 
    
prog returns [List<Mod> result]
	: mods {$result = $mods.result; };
	
mods returns [List<Mod> result]
	: {$result = new LinkedList();} 
	m1=mod {$result.add($m1.result);}
	(',' m2=mod {$result.add($m2.result);})*;
mod returns [Mod result]
	: dictmod {$result = $dictmod.result;} 
	| primmod {$result = $primmod.result;}
	| nomod {$result = NullMod.INSTANCE;};
dictmod returns [Mod result] 
	: {DictModFactory f = new DictModFactory();}
	'{' (i1=dictmoditem {f.addPut($i1.key, $i1.mod);})? 
	(',' i2=dictmoditem {f.addPut($i2.key, $i2.mod);} )* '}'
	{$result = f.create();};
dictmoditem returns [Object key, Mod mod] 
	: prim {$key = $prim.result;}
	('->' | '=')
	m=mod {$mod = $m.result;};
primmod returns [Mod result]
	 : '!'? prim {$result = new PrimMod($prim.result);};
prim returns [Object result]
	: NAME {$result = $NAME.text;} 
	| STRING {$result = $STRING.text.substring(1, $STRING.text.length() - 1);}
	| NUMBER {$result = new Integer($NUMBER.text);}
	| NULL {$result = null;}
	| TRUE {$result = true;}
	| FALSE {$result = false;};
nomod : NOMOD | VOID; 
 